package com.edu.boot301demo.listener;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.stereotype.Component;

import java.time.Duration;

/**
 * 各种回调监听器
 * SpringApplicationRunListener: 感知特定阶段：感知全阶段的生命周期。
 * ---- META-INF/spring.factories
 * ApplicationRunner: 感知特定阶段：感知应用就绪 Ready
 * ---- @Bean
 * CommandLineRunner: 感知特定阶段：感知应用就绪 Ready
 * ---- @Bean
 * BootstrapRegistryInitializer: 感知特定阶段：感知引导初始化
 * ---- META-INF/spring.factories
 * ApplicationContextInitializer: 感知 IoC 容器初始化
 * ---- META-INF/spring.factories
 * ApplicationListener: 感知全阶段：基于事件机制，感知事件。 AOP 环绕 等。
 * ---- META-INF/spring.factories
 * ---- @Bean 、 @EventListener
 * ---- SpringApplication.addListeners(...) / SpringApplicationBuilder.listeners(...)
 */
@Component
@Slf4j
public class MyAppListener implements SpringApplicationRunListener {
    // 1.引导：利用BootStrapContext 引导整个项目启动
    // starting: 应用开始，SpringApplication的run方法一调用，只要有了 BootStrapContext 就会进入这个方法
    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("============启动开始==========");
    }

    // environmentPrepared: 环境准备好（把启动参数等绑定到环境变量中），但是ioc还没有创建【调一次】
    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        System.out.println("============环境准备完成==========");
    }

    // 2. 启动
    // contextPrepared: ioc创建并准备好，但是sources(主配置类)还没有加载。并关闭引导上下文；组件都没有创建【调一次】
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("============上下文准备完成==========");
    }

    // contextLoaded: ioc容器加载。主配置类加载进去了。但是ioc容器还没有刷新（我们的 bean 没创建）
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("============上下文加载完成==========");
    }
    // 在此之前，容器中还没有创建bean

    // started: 容器刷新完成。所有bean创建完成，属性注入完成。但是bean还没有初始化。runner还没有执行。
    @Override
    public void started(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("============上下文启动完成==========");
    }

    // ready: 容器刷新完成。所有bean创建完成，属性注入完成，bean初始化完成。runner调用完成。
    @Override
    public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("============上下文就绪完成==========");
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("============上下文启动失败==========");
    }

    // 3. 运行
}
